package com.example.demo.pojo;

import lombok.Data;

import java.io.Serializable;
import java.util.*;
/**
 * @author luolinila
 */
@Data
public class Poker implements Serializable {
    public String value;
    public String color;
    static public String[] values = {"2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"};
    static public String[] colors = {"cube", "plum", "heart", "spade"};

    public Poker() {};
    public Poker(String value, String color) {
        this.value = value;
        this.color = color;
    }

    public static int compare(Poker p1, Poker p2) {
        int sign = compareNotColor(p1, p2);
        if (sign != 0) {
            return sign;
        }
        return p1.getColorIndex() - p2.getColorIndex();
    }

    public int compare(Poker p1) {
        return compare(this,p1);
    }

    public static int compareNotColor(Poker p1, Poker p2) {
        return p1.getValueIndex() - p2.getValueIndex();
    }

    public int compareNotColor(Poker p1) {
        return compareNotColor(this,p1);
    }

    public static int getValueIndex(String value) {
        for (int i = 0; i < values.length; i++) {
            if (value.compareTo(values[i]) == 0) {
                return i;
            }
        }
        return -1;
    }

    public static int getColorIndex(String color) {
        for (int i = 0; i < colors.length; i++) {
            if (color.compareTo(colors[i]) == 0) {
                return i;
            }
        }
        return -1;
    }

    public int getValueIndex() {
        return getValueIndex(value);
    }

    public int getColorIndex() {
        return getColorIndex(color);
    }

    //获取手牌牌型
    public static HandPoker evaluateHand(List<Poker> handPokers, List<Poker> communityPokers) {
        List<Poker> allPokers = new ArrayList<>(handPokers);
        allPokers.addAll(communityPokers);
        HashMap<String, Integer> rankCount = new HashMap<>();
        HashMap<String, Integer> suitCount = new HashMap<>();
        for (Poker p : allPokers) {
            rankCount.put(p.value, rankCount.getOrDefault(p.value, 0) + 1);
            suitCount.put(p.color, suitCount.getOrDefault(p.color, 0) + 1);
        }
        boolean isFlush = suitCount.values().stream().allMatch(s -> s >= 5);
        List<Integer> ranks = new ArrayList<>();
        for (String rank : rankCount.keySet()) {
            ranks.add(getColorIndex(rank));
        }
        Collections.sort(ranks, Collections.reverseOrder());
        boolean isStraight = isStraight(ranks);
        if (isFlush && isStraight && ranks.contains(getValueIndex("A"))) {
            return new HandPoker(10, ranks);
        }else if (isFlush && isStraight) {
            return new HandPoker(9, ranks);
        }else if (rankCount.containsValue(4)) {
            return new HandPoker(8, ranks);
        }else if (rankCount.containsValue(3) && rankCount.containsValue(2)) {
            return new HandPoker(7, ranks);
        }else if (isFlush) {
            return new HandPoker(6, ranks);
        }else if (isStraight) {
            return new HandPoker(5, ranks);
        }else if (rankCount.containsValue(3)) {
            return new HandPoker(4, ranks);
        }else if (Collections.frequency(new ArrayList<>(rankCount.values()), 2) == 2) {
            return new HandPoker(3, ranks);
        }else if (rankCount.containsValue(2)) {
            return new HandPoker(2, ranks);
        }else {
            return new HandPoker(1, ranks);
        }
    }

    public static boolean isStraight(List<Integer> ranks) {
        HashSet<Integer> uniqueRanks = new HashSet<>(ranks);
        for (int i = 0; i < uniqueRanks.size() - 4; i++) {
            if (uniqueRanks.contains(ranks.get(i) - 1) &&
                uniqueRanks.contains(ranks.get(i) - 2) &&
                uniqueRanks.contains(ranks.get(i) - 3) &&
                uniqueRanks.contains(ranks.get(i) - 4)) {
                return true;
            }
        }
        return false;
    }

    public static int compareHand(List<Poker> hand1, List<Poker> hand2, List<Poker> communityPokers) {
        return evaluateHand(hand1, communityPokers).compareTo(evaluateHand(hand2, communityPokers));
    }
}
